package com.agileai.miscdp.hotweb.ui.celleditors;

import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.widgets.Table;

/**
 * 光标移动辅助类
 */
public class TableViewerKeyboardSupporter {
	protected TableViewer fTableViewer = null;

	public TableViewerKeyboardSupporter(TableViewer tableViewer) {
		fTableViewer = tableViewer;
	}

	/**
	 * After the cell editors have been set on tableviewer, this method should
	 * be called to start giving keyboard support.
	 */
	public void startSupport() {
		/* add table key listener */
		getTable().addKeyListener(new TableKeyListener(this));

		/* add table traverse listener */
		getTable().addTraverseListener(new TableTraverseListener(this));

		/* add table-textcelleditors key and traverse listeners */
		CellEditor[] cellEditors = fTableViewer.getCellEditors();
		if (cellEditors != null) {
			for (int colIndex = 0; colIndex < cellEditors.length; colIndex++) {
				CellEditor cellEditor = cellEditors[colIndex];
				if (cellEditor != null) {
					cellEditor.getControl().addKeyListener(
							new CellEditorKeyListener(this, cellEditor,
									colIndex));
					cellEditor.getControl().addTraverseListener(
							new CellEditorTraverseListener(this, cellEditor,
									colIndex));
				}
			}
		}
	}

	protected TableViewer getTableViewer() {
		return fTableViewer;
	}

	protected Table getTable() {
		return fTableViewer.getTable();
	}

	protected int nextColumn(int column) {
		return (column >= getTable().getColumnCount() - 1) ? 0 : column + 1;
	}

	protected int prevColumn(int column) {
		return (column <= 0) ? getTable().getColumnCount() - 1 : column - 1;
	}

	protected void editColumnOrNextPossible(final int column) {
		Object selectedElem = getSelectedElement();
		if (selectedElem == null)
			return;

		int nextColumn = column;
		do {
			fTableViewer.editElement(selectedElem, nextColumn);
			if (fTableViewer.isCellEditorActive())
				return;
			nextColumn = nextColumn(nextColumn);
		} while (nextColumn != column);
	}

	protected void editColumnOrPrevPossible(int column) {
		Object selectedElem = getSelectedElement();
		if (selectedElem == null)
			return;

		int prevColumn = column;
		do {
			fTableViewer.editElement(selectedElem, prevColumn);
			if (fTableViewer.isCellEditorActive())
				return;
			prevColumn = prevColumn(prevColumn);
		} while (prevColumn != column);
	}

	private Object getSelectedElement() {
		IStructuredSelection selection = (IStructuredSelection) fTableViewer
				.getSelection();
		if (selection == null || selection.isEmpty())
			return null;

		return selection.getFirstElement();
	}
}

class CellEditorKeyListener extends KeyAdapter {
	private TableViewerKeyboardSupporter fKeyBoardSupporter = null;

	private CellEditor fEditor = null;

	private int fEditorColumn = -1;

	public CellEditorKeyListener(
			TableViewerKeyboardSupporter keyBoardSupporter, CellEditor editor,
			int editorColumn) {
		fKeyBoardSupporter = keyBoardSupporter;
		fEditor = editor;
		fEditorColumn = editorColumn;
	}

	public void keyPressed(KeyEvent e) {
		if (e.stateMask == SWT.MOD1 || e.stateMask == SWT.MOD2) {
			if (e.keyCode == SWT.ARROW_UP || e.keyCode == SWT.ARROW_DOWN) {
				// allow starting multi-selection even if in edit mode
				fEditor.deactivate();
				e.doit = false;
				return;
			}
		}

		if (e.stateMask != SWT.NONE)
			return;

		switch (e.keyCode) {
		case SWT.ARROW_DOWN:
			e.doit = false;
			int nextRow = fKeyBoardSupporter.getTable().getSelectionIndex() + 1;
			if (nextRow >= fKeyBoardSupporter.getTable().getItemCount())
				break;
			fKeyBoardSupporter.getTable().setSelection(nextRow);
			fKeyBoardSupporter.editColumnOrPrevPossible(fEditorColumn);
			break;

		case SWT.ARROW_UP:
			e.doit = false;
			int prevRow = fKeyBoardSupporter.getTable().getSelectionIndex() - 1;
			if (prevRow < 0)
				break;
			fKeyBoardSupporter.getTable().setSelection(prevRow);
			fKeyBoardSupporter.editColumnOrPrevPossible(fEditorColumn);
			break;

		case SWT.F2:
			e.doit = false;
			fEditor.deactivate();
			break;
		}
	}
}

class CellEditorTraverseListener implements TraverseListener {
	private TableViewerKeyboardSupporter fKeyBoardSupporter = null;

	private CellEditor fEditor = null;

	private int fEditorColumn = -1;

	public CellEditorTraverseListener(
			TableViewerKeyboardSupporter keyBoardSupporter, CellEditor editor,
			int editorColumn) {
		fKeyBoardSupporter = keyBoardSupporter;
		fEditor = editor;
		fEditorColumn = editorColumn;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.swt.events.TraverseListener#keyTraversed(org.eclipse.swt.events.TraverseEvent)
	 */
	public void keyTraversed(TraverseEvent e) {

		switch (e.detail) {
		case SWT.TRAVERSE_TAB_NEXT:
			fKeyBoardSupporter.editColumnOrNextPossible(fKeyBoardSupporter
					.nextColumn(fEditorColumn));
			e.detail = SWT.TRAVERSE_NONE;
			break;

		case SWT.TRAVERSE_TAB_PREVIOUS:
			fKeyBoardSupporter.editColumnOrPrevPossible(fKeyBoardSupporter
					.prevColumn(fEditorColumn));
			e.detail = SWT.TRAVERSE_NONE;
			break;

		case SWT.TRAVERSE_ESCAPE:
			fKeyBoardSupporter.getTableViewer().cancelEditing();
			e.detail = SWT.TRAVERSE_NONE;
			break;

		case SWT.TRAVERSE_RETURN:
			fEditor.deactivate();
			e.detail = SWT.TRAVERSE_NONE;
			break;

		default:
			break;
		}
	}
}

class TableTraverseListener implements TraverseListener {
	private TableViewerKeyboardSupporter fKeyBoardSupporter = null;

	public TableTraverseListener(TableViewerKeyboardSupporter keyBoardSupporter) {
		fKeyBoardSupporter = keyBoardSupporter;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.swt.events.TraverseListener#keyTraversed(org.eclipse.swt.events.TraverseEvent)
	 */
	public void keyTraversed(TraverseEvent e) {
		if (e.detail == SWT.TRAVERSE_RETURN && e.stateMask == SWT.NONE) {
			fKeyBoardSupporter.editColumnOrNextPossible(0);
			e.detail = SWT.TRAVERSE_NONE;
		}
	}
}

class TableKeyListener extends KeyAdapter {
	private TableViewerKeyboardSupporter fKeyBoardSupporter = null;

	public TableKeyListener(TableViewerKeyboardSupporter keyBoardSupporter) {
		fKeyBoardSupporter = keyBoardSupporter;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events.KeyEvent)
	 */
	public void keyPressed(KeyEvent e) {
		if (e.keyCode == SWT.F2 && e.stateMask == SWT.NONE) {
			fKeyBoardSupporter.editColumnOrNextPossible(0);
			e.doit = false;
		}
	}
}
